#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task.hpp"

class Channel
{
public:
    Channel(int wfd, pid_t id, const std::string &name)
        : _wfd(wfd), _subprocessid(id), _name(name)
    {}

    int GetWfd() { return _wfd; }
    pid_t GetProcessId() { return _subprocessid; }
    std::string GetName() { return _name; }

    void CloseChannel()
    {
        close(_wfd);
    }

    void Wait()
    {
        pid_t rid = waitpid(_subprocessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait " << rid << " process" << std::endl;
        }
    }

    ~Channel()
    {
    }

private:
    int _wfd;
    pid_t _subprocessid;
    std::string _name;
};

// void work(int rfd)
// {
//     while (true)
//     {
//         int command = 0;
//         int n = read(rfd, &command, sizeof(command));
//         if (n == sizeof(int))
//         {
//             // 哪个进程处理的任务
//             std::cout << "pid is: " << getpid() << std::endl;
//             ExcuteTask(command);
//         }
//         else if (n == 0)
//         {
//             std::cout << "subprocess: " << getpid() << " quit" << std::endl;
//             // 管道读完后节结束
//             break;
//         }
//     }
// }


// 形参类型和命名规范:
// const & ：输出
// & ：输入输出型参数
// * ：输出型参数

// task_t：回调函数
void CreateChannelAndSub(int num, std::vector<Channel> *channels, task_t task)
{
    // 1.创建信道和子进程
    for (int i = 0; i < num; i++)
    {
        // 1.创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
            std::cerr << "pipe creat fail!" << std::endl;

        // 2.创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            // child -- read
            // 关闭不需要的进程
            close(pipefd[1]);

            // 把管道的读端，重定向到标准输入
            // 把管道的逻辑和子进程执行任务的逻辑进行解耦
            dup2(pipefd[0], 0); 
            task();
            //work();

            close(pipefd[0]);
            exit(0);
        }

        // 3.构建一个channel名称
        std::string channel_name = "channel-" + std::to_string(i);

        // father -- write
        // 关闭不需要的进程
        close(pipefd[0]);
        channels->push_back(Channel(pipefd[1], id, channel_name));
    }
}

// 形成 0~channelnum 的编号,一直轮询
int SelectChannel(int channelnum)
{
    static int next = 0;
    int channel = next;
    next++;

    next %= channelnum;
    return channel;
}

// 发送任务
void SendTaskCommand(Channel &channel, int taskcommand)
{
    write(channel.GetWfd(), &taskcommand, sizeof(taskcommand));
}

void CtrProcessOnce(std::vector<Channel>& channels)
{
    sleep(1);
    // a.选择一个任务
    int taskcommand = SelectTask();
    // b.选择一个信道和进程
    int channel_index = SelectChannel(channels.size());
    // c.发送任务
    SendTaskCommand(channels[channel_index], taskcommand);

    std::cout << std::endl;

    // 打印出发送的哪个任务，发送给哪个channel，哪个子进程
    std::cout << "taskcommand: " << taskcommand << " channel: " << channels[channel_index].GetName()
              << " sub process: " << channels[channel_index].GetProcessId() << std::endl;
}

void CtrProcess(std::vector<Channel> &channels, int times = -1)
{
    if(times > 0)
    {
        while(times--) CtrProcessOnce(channels);
    }
    else
    {
        while(true) CtrProcessOnce(channels);
    }
}

void CleanChannel(std::vector<Channel> &channels)
{
    // 关闭所有写端
    for (auto &channel : channels)
    {
        channel.CloseChannel();
        channel.Wait();
    }
    // 注意
    for (auto &channel : channels)
    {
        // 子进程回收
        channel.Wait();
    }
}

// argc就是argv[]里的元素个数
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " processnum" << std::endl;
        return 1;
    }

    int num = std::stoi(argv[1]);
    LoadTask(); // 加载任务

    std::vector<Channel> channels;
    // 1.创建信道和子进程
    CreateChannelAndSub(num, &channels, work);

    // 2.通过channel控制子进程
    CtrProcess(channels, 10);

    // 3.回收管道和子进程
    CleanChannel(channels);

    return 0;
}